﻿using Serilog;
using Serilog.Debugging;
using Serilog.Events;
using Serilog.Formatting.Json;
using Serilog.Sinks.Elasticsearch;
using Serilog.Sinks.File;
using Serilog.Sinks.SystemConsole.Themes;
using System;
using System.Threading;


namespace Sustainalytics.Alerts.AlertsEngine
{
    public sealed class AlertsEngineSerilog
    {
        public static Lazy<AlertsEngineSerilog> _lazyLog = new Lazy<AlertsEngineSerilog>(InitLog, LazyThreadSafetyMode.ExecutionAndPublication);
        private readonly ILogger _logger;


        public static AlertsEngineSerilog Log
        {
            get
            {
                return _lazyLog.Value;
            }
        }

        public static AlertsEngineSerilog InitLog()
        {
            var log = new AlertsEngineSerilog();
            log.Ping();
            return log;

        }

        public AlertsEngineSerilog()
        {
            var loggerConfig = new LoggerConfiguration()
                  .MinimumLevel.Debug()
                  .WriteTo.Console(theme: SystemConsoleTheme.Literate)
                  .WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri("http://localhost:9200")) // for the docker-compose implementation
                  {
                      IndexFormat = "testalerts-{0:yyyy.MM.dd}",
                      AutoRegisterTemplate = true,
                      //BufferBaseFilename = "./buffer",
                      RegisterTemplateFailure = RegisterTemplateRecovery.IndexAnyway,
                      FailureCallback = e => Console.WriteLine("Unable to submit event " + e.MessageTemplate),
                      EmitEventFailure = EmitEventFailureHandling.WriteToSelfLog |
                                         EmitEventFailureHandling.WriteToFailureSink |
                                         EmitEventFailureHandling.RaiseCallback,
                      FailureSink = new FileSink("../failuresAlerts-" + DateTime.Now.ToString("yyyy-dd-M--HH-mm-ss") + ".txt", new JsonFormatter(), null)
                  });
            _logger = loggerConfig.CreateLogger();

            SelfLog.Enable(Console.Error);
        }

        public void Ping()
        {
            var eventId = 1;
            _logger.Debug("Ping {eventId}", eventId);
            
        }

        public void Exception(Guid SessionId, string message, Exception ex)
        {
            if (ex != null)
                this.Exception(SessionId, message, ex.GetType().ToString(), ex.Message, ex.ToString());
        }

        public void Exception(Guid SessionId, string message, string exceptionType, string exceptionMessage, string exceptionInformation)
        {
            var eventId = 2;
            if (_logger.IsEnabled(LogEventLevel.Error))
                _logger.Error("Exception {evenId}, {message}, {exceptionType}, {exceptionMessage}, {exceptionInformation}", eventId, message, exceptionType,exceptionMessage,exceptionInformation);
        }

        public void Test(string controllerName, string httpMethod, int statusCode, string reasonPhrase)
        {
            var eventId = 3;
            if (_logger.IsEnabled(LogEventLevel.Information))
            {
                _logger.Information("Test {eventId}, {controllerName}, {httpMethod}, {statusCode}, {reasonPhrase}", eventId, controllerName, httpMethod, statusCode, reasonPhrase);
            }
        }

        public void InOutEvent(Guid sessionId)
        {
            var eventId = 4;
            if (_logger.IsEnabled(LogEventLevel.Information))
            {
                _logger.Information("InOutEvent {evenId}, {sessionId}", eventId, sessionId);
            }
        }

        public void FileRead(Guid sessionId, DateTime nextAlertSessionSendingDate, DateTime lastSemiMonthlyAlertSession, string unservedClients)
        {
            var eventId = 5;
            if (_logger.IsEnabled(LogEventLevel.Information))
            {
                _logger.Information("FileRead {eventId}, {sessionId}, {nextAlertSessionSendingDate}, {lastSemiMonthlyAlertSession}, {unservedClients}",
                    eventId,
                    sessionId,
                    nextAlertSessionSendingDate.ToString(System.Globalization.CultureInfo.InvariantCulture),
                    lastSemiMonthlyAlertSession.ToString(System.Globalization.CultureInfo.InvariantCulture),
                    unservedClients
                    );
            }
        }

        public void BlobRead(Guid sessionId, DateTime nextAlertSessionSendingDate, DateTime lastSemiMonthlyAlertSession)
        {
            var eventId = 6;
            if (_logger.IsEnabled(LogEventLevel.Information))
            {
                _logger.Information("BlobRead {eventId}, {sessionId}, {nextAlertSessionSendingDate}, {lastSemiMonthlyAlertSession}",
                    eventId,
                    sessionId,
                    nextAlertSessionSendingDate.ToString(System.Globalization.CultureInfo.InvariantCulture),
                    lastSemiMonthlyAlertSession.ToString(System.Globalization.CultureInfo.InvariantCulture)
                    );
            }
        }

        public void MongoEvent(string className, string dbName, string collectionName, string opName, string args, string result)
        {
            var eventId = 6;
            if (_logger.IsEnabled(LogEventLevel.Information))
            {
                _logger.Information("MongoEvent {eventId}, {className}, {dbName}, {collectionName}, {opName}, {args}, {result}",
                    eventId,
                    className,
                    dbName,
                    collectionName,
                    opName,
                    args,
                    result);
            }
        }

        public void CompletedSuccesfully(Guid sessionId)
        {
            var eventId = 9;
            if (_logger.IsEnabled(LogEventLevel.Information))
            {
                _logger.Information("CompletedSuccesfully {eventId}, {sessionId}",
                    eventId,
                    sessionId);
            }
        }

        public void EmailSent(Guid sessionId, string user, string email)
        {
            var eventId = 10;
            if (_logger.IsEnabled(LogEventLevel.Information))
            { 
                _logger.Information("EmailSent {eventId}, {sessionId}, {user}, {mail}",
                    eventId,
                    user,
                    email);
            }
        }
        public void SubscriptionWithoutFeatureUniverses(Guid sessionId, string subscriberId)
        {
            var eventId = 11;
            if (_logger.IsEnabled(LogEventLevel.Verbose))
            {
                _logger.Verbose("SubscriptionWithoutFeatureUniverses {eventId}, {sessionId}, {subscriberId}",
                    eventId,
                    sessionId,
                    subscriberId
                    );
            }
        }

        public void SubscriptionWithoutClaims(Guid sessionId, string subscriberId)
        {
            var eventId = 12;
            if (_logger.IsEnabled(LogEventLevel.Verbose))
            {
                _logger.Verbose("SubscriptionWithoutClaims {eventId}, {sessionId}, {subscriberId}", eventId, sessionId, subscriberId);
            }
        }

        public void SubscriptionAccepted(Guid sessionId, string subscriberId)
        {
            var eventId = 13;
            if (_logger.IsEnabled(LogEventLevel.Verbose))
            {
                _logger.Verbose("SubscriptionAccepted {eventId}, {sessionId}, {subscriberId}", eventId, sessionId, subscriberId);
            }
        }

        public void SubscriptionRejectedBecauseUserAccess(Guid sessionId, string subscriberId)
        {
            var eventId = 14;
            if (_logger.IsEnabled(LogEventLevel.Verbose))
            {
                _logger.Verbose("SubscriptionRejectedBecauseUserAccess {eventId}, {sessionId}, {subscriberId}", eventId, sessionId, subscriberId);
            }
        }
        public void ProcessAlertStarted(Guid sessionId)
        {
            var eventId = 15;
            if (_logger.IsEnabled(LogEventLevel.Information))
            {
                _logger.Information("Process alerts started {eventId}, {sessionId}", eventId, sessionId);
            }
        }
        public void ProcessAlertEnded(Guid sessionId)
        {
            var eventId = 16;
            if (_logger.IsEnabled(LogEventLevel.Information))
            {
                _logger.Information("Process alerts ended {eventId}, {sessionId}", eventId, sessionId);
            }
        }

        public void NoNeedToProcess(Guid sessionId)
        {
            var eventId = 17;
            if (_logger.IsEnabled(LogEventLevel.Information))
            {
                _logger.Information("No need to process {eventId}, {sessionId}", eventId, sessionId);
            }
        }
        public void SubscriptionRejectedBecauseUserHasInvalidAccount(Guid sessionId, string subscriberId)
        {
            var eventId = 18;
            if (_logger.IsEnabled(LogEventLevel.Verbose))
            {
                _logger.Verbose("SubscriptionRejectedBecauseUserHasInvalidAccount {eventId}, {sessionId}, {subscriberId}", eventId, sessionId, subscriberId);
            }
        }

        public void SubscriptionWithoutCompanies(Guid sessionId, Guid subscriberId, Guid compId)
        {
            var eventId = 19;
            if (_logger.IsEnabled(LogEventLevel.Information))
            {
                _logger.Information("SubscriptionWithoutCompanies {eventId}, {sessionId}, {subscriberId} {compId}", eventId, sessionId, subscriberId, compId);
            }
        }

        public void NoPorfolioForSubscription(Guid sessionId, Guid subscriberId)
        {
            var eventId = 21;
            if (_logger.IsEnabled(LogEventLevel.Information))
            { 
                _logger.Information("NoPorfolioForSubscription {eventId}, {sessionId}, {subscriberId}.", eventId, sessionId, subscriberId);
            }
        }

        public void NoLastSync(Guid sessionId)
        {
            var eventId = 21;
            if (_logger.IsEnabled(LogEventLevel.Information))
            {
                _logger.Information("NoLastSync {eventId}, {sessionId}", eventId, sessionId);
            }
        }

        public void LastSyncNotEnded(Guid sessionId)
        {
            var eventId = 23;
            if (_logger.IsEnabled(LogEventLevel.Information))
            {
                _logger.Information("LastSyncNotEnded {eventId}, {sessionId}", eventId, sessionId);
            }
        }

        public void LastSyncOlderThan24Hours(Guid sessionId)
        {
            var eventId = 24;
            if (_logger.IsEnabled(LogEventLevel.Information))
            {
                _logger.Information("LastSyncNotEnded {eventId}, {sessionId}", eventId, sessionId);
            }
        }


        public void AlertWithoutCompanyInCorporateData(Guid sessionId)
        {
            var eventId = 25;
            if (_logger.IsEnabled(LogEventLevel.Information))
            {
                _logger.Information("AlertWithoutCompanyInCorporateData {eventId}, {sessionId}", eventId, sessionId);
            }
        }
    }

}
